package org.smart4j.framework.common.aop;

import lombok.extern.slf4j.Slf4j;
import org.smart4j.framework.common.util.AnnotationUtil;
import org.smart4j.framework.common.util.DBUtil;

import java.lang.reflect.Method;

/**
 * 事务代理类
 * 为什么不写成切面？
 * 因为在AOPHelper中是对@Aspect注解中value注解进行代理的（基于类代理），无法根据@Transaction注解找到对应的代理类
 *
 * @author YooLin1c
 * @version 1.0.0
 * @since 2018-02-05 22:33
 */
@Slf4j
public class TransactionProxy implements Proxy {
    /**
     * 保证同一线程中事务控制相关逻辑只会执行一次
     */
    private static final ThreadLocal<Boolean> FLAG_HOLDER = ThreadLocal.withInitial(() -> false);

    @Override
    public Object doProxy(ProxyChain proxyChain) throws Throwable {
        Object result;
        Boolean flag = FLAG_HOLDER.get();
        Method method = proxyChain.getTargetMethod();
        if (!flag && AnnotationUtil.isTransactionAnnotated(method)) {
            FLAG_HOLDER.set(true);
            try {
                DBUtil.beginTransaction();
                result = proxyChain.doProxyChain();
                DBUtil.commitTransaction();
            } catch (Throwable throwable) {
                DBUtil.rollbackTransaction();
                log.error("roll back transaction caused error!", throwable);
                throw new RuntimeException(throwable);
            } finally {
                //事务执行结束后移除本地线程变量中的标志
                FLAG_HOLDER.remove();
            }
        } else {
            result = proxyChain.doProxyChain();
        }
        return result;
    }
}
